From e9d1a942d14de642ae9dae5974bffa0e5fdd6ec6 Mon Sep 17 00:00:00 2001 From: ElNounch Date: Mon, 22 Aug 2016 19:43:43 +0200 Subject: Delay EntityChangedWorld players' callback until Entity fully linked to world (#3330) Otherwise, some API calls just don't seem to happen .gitignore tweak for test executables --- .gitignore | 1 + src/Entities/Player.cpp | 3 +-- src/World.cpp | 35 +++++++++++++++++++++++++---------- src/World.h | 8 +++++--- 4 files changed, 32 insertions(+), 15 deletions(-) diff --git a/.gitignore b/.gitignore index eb63f620e..bb046dd98 100644 --- a/.gitignore +++ b/.gitignore @@ -68,6 +68,7 @@ Makefile *.a *.d *.so +tests/*/*-exe BuildInfo.h CMakeCache.txt CMakeFiles diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index e4c0fdaa5..50bec3608 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -1827,8 +1827,7 @@ bool cPlayer::DoMoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn, Vector3d ParentChunk->GetPosX(), ParentChunk->GetPosZ() ); ParentChunk->RemoveEntity(this); - a_World->AddPlayer(this); - cRoot::Get()->GetPluginManager()->CallHookEntityChangedWorld(*this, a_OldWorld); + a_World->AddPlayer(this, &a_OldWorld); // New world will appropriate and announce client at his next tick }); return true; } diff --git a/src/World.cpp b/src/World.cpp index c687e9549..c10cb52e9 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -2990,10 +2990,10 @@ void cWorld::CollectPickupsByPlayer(cPlayer & a_Player) -void cWorld::AddPlayer(cPlayer * a_Player) +void cWorld::AddPlayer(cPlayer * a_Player, cWorld * a_OldWorld) { cCSLock Lock(m_CSPlayersToAdd); - m_PlayersToAdd.push_back(a_Player); + m_PlayersToAdd.emplace_back(a_Player, a_OldWorld); } @@ -3010,7 +3010,10 @@ void cWorld::RemovePlayer(cPlayer * a_Player, bool a_RemoveFromChunk) } { cCSLock Lock(m_CSPlayersToAdd); - m_PlayersToAdd.remove(a_Player); + m_PlayersToAdd.remove_if([&](const std::pair< cPlayer *, cWorld * > & value) -> bool + { + return (value.first == a_Player); + }); } { cCSLock Lock(m_CSPlayers); @@ -3895,7 +3898,7 @@ void cWorld::AddQueuedPlayers(void) ASSERT(m_TickThread.IsCurrentThread()); // Grab the list of players to add, it has to be locked to access it: - cPlayerList PlayersToAdd; + cAwaitingPlayerList PlayersToAdd; { cCSLock Lock(m_CSPlayersToAdd); std::swap(PlayersToAdd, m_PlayersToAdd); @@ -3904,8 +3907,9 @@ void cWorld::AddQueuedPlayers(void) // Add all the players in the grabbed list: { cCSLock Lock(m_CSPlayers); - for (auto Player : PlayersToAdd) + for (auto & AwaitingPlayer : PlayersToAdd) { + auto & Player = AwaitingPlayer.first; ASSERT(std::find(m_Players.begin(), m_Players.end(), Player) == m_Players.end()); // Is it already in the list? HOW? LOGD("Adding player %s to world \"%s\".", Player->GetName().c_str(), m_WorldName.c_str()); @@ -3922,9 +3926,10 @@ void cWorld::AddQueuedPlayers(void) // Add all the players' clienthandles: { cCSLock Lock(m_CSClients); - for (cPlayerList::iterator itr = PlayersToAdd.begin(), end = PlayersToAdd.end(); itr != end; ++itr) + for (auto & AwaitingPlayer : PlayersToAdd) { - cClientHandlePtr Client = (*itr)->GetClientHandlePtr(); + auto & Player = AwaitingPlayer.first; + cClientHandlePtr Client = Player->GetClientHandlePtr(); if (Client != nullptr) { m_Clients.push_back(Client); @@ -3933,16 +3938,26 @@ void cWorld::AddQueuedPlayers(void) } // Lock(m_CSClients) // Stream chunks to all eligible clients: - for (cPlayerList::iterator itr = PlayersToAdd.begin(), end = PlayersToAdd.end(); itr != end; ++itr) + for (auto & AwaitingPlayer : PlayersToAdd) { - cClientHandle * Client = (*itr)->GetClientHandle(); + auto & Player = AwaitingPlayer.first; + cClientHandle * Client = Player->GetClientHandle(); if (Client != nullptr) { Client->SendPlayerMoveLook(); Client->SendHealth(); - Client->SendWholeInventory(*(*itr)->GetWindow()); + Client->SendWholeInventory(*Player->GetWindow()); } } // for itr - PlayersToAdd[] + + // Call EntityChangedWorld callback on all eligible clients + for (auto & AwaitingPlayer : PlayersToAdd) + { + if (AwaitingPlayer.second != nullptr) + { + cRoot::Get()->GetPluginManager()->CallHookEntityChangedWorld(*(static_cast (AwaitingPlayer.first)), *AwaitingPlayer.second); + } + } } diff --git a/src/World.h b/src/World.h index c1794b159..a00e181b6 100644 --- a/src/World.h +++ b/src/World.h @@ -61,6 +61,7 @@ class cBroadcaster; typedef std::list< cPlayer * > cPlayerList; +typedef std::list< std::pair< cPlayer *, cWorld * > > cAwaitingPlayerList; typedef SharedPtr cSetChunkDataPtr; // TODO: Change to unique_ptr once we go C++11 typedef std::vector cSetChunkDataPtrs; @@ -262,8 +263,9 @@ public: /** Adds the player to the world. Uses a queue to store the player object until the Tick thread processes the addition event. - Also adds the player as an entity in the chunkmap, and the player's ClientHandle, if any, for ticking. */ - void AddPlayer(cPlayer * a_Player); + Also adds the player as an entity in the chunkmap, and the player's ClientHandle, if any, for ticking. + If a_OldWorld is provided, a corresponding ENTITY_CHANGED_WORLD event is triggerred after the addition. */ + void AddPlayer(cPlayer * a_Player, cWorld * a_OldWorld = nullptr); /** Removes the player from the world. Removes the player from the addition queue, too, if appropriate. @@ -1006,7 +1008,7 @@ private: cCriticalSection m_CSPlayersToAdd; /** List of players that are scheduled for adding, waiting for the Tick thread to add them. */ - cPlayerList m_PlayersToAdd; + cAwaitingPlayerList m_PlayersToAdd; /** CS protecting m_SetChunkDataQueue. */ cCriticalSection m_CSSetChunkDataQueue; -- cgit v1.2.3